#include "InputLayer.h"

using namespace std;

cInputLayer* cInputLayer::m_pGlobalILayer = NULL;

cInputLayer::cInputLayer(int setKeyboard, int setMouse)
{
    if (!m_pGlobalILayer)
    {        
        this->setKeyboard = setKeyboard;    
        this->setMouse = setMouse;

        this->keyboardLenght = 110;
        this->mouseLenght = 8;

        this->xPos = 0;
        this->yPos = 0;
        this->xPosRelative = 0;
        this->yPosRelative = 0;
        this->eventMouseX = 0;
	this->eventMouseY = 0;
        
        if(this->setKeyboard)
        {
            this->keyboard.reserve(110);
            this->eventKeyPressed.reserve(110);
            this->previousKeyboardState.reserve(110);
            this->currentKeyboardState.reserve(110);

            this->keyboard[0] = 0;
            this->keyboard[1] = 1;
            this->keyboard[2] = 2;
            this->keyboard[3] = 3;
            this->keyboard[4] = 4;
            this->keyboard[5] = 5;
            this->keyboard[6] = 6;
            this->keyboard[7] = 7;
            this->keyboard[8] = 8;
            this->keyboard[9] = 9;
            this->keyboard[10] = 'Q';
            this->keyboard[11] = 'W';
            this->keyboard[12] = 'E';
            this->keyboard[13] = 'R';
            this->keyboard[14] = 'T';
            this->keyboard[15] = 'Y';
            this->keyboard[16] = 'U';
            this->keyboard[17] = 'I';
            this->keyboard[18] = 'O';
            this->keyboard[19] = 'P';
            this->keyboard[20] = 'A';
            this->keyboard[21] = 'S';
            this->keyboard[22] = 'D';
            this->keyboard[23] = 'F';
            this->keyboard[24] = 'G';
            this->keyboard[25] = 'H';
            this->keyboard[26] = 'J';
            this->keyboard[27] = 'K';
            this->keyboard[28] = 'L';
            this->keyboard[29] = 'Z';
            this->keyboard[30] = 'X';
            this->keyboard[31] = 'C';
            this->keyboard[32] = 'V';
            this->keyboard[33] = 'B';
            this->keyboard[34] = 'N';
            this->keyboard[35] = 'M';
            this->keyboard[36] = ',';
            this->keyboard[37] = '.';
            this->keyboard[38] = '-';
            this->keyboard[39] = GLFW_KEY_SPACE;
            this->keyboard[40] = GLFW_KEY_SPECIAL;
            this->keyboard[41] = GLFW_KEY_ESC;
            this->keyboard[42] = GLFW_KEY_F1;
            this->keyboard[43] = GLFW_KEY_F2;
            this->keyboard[44] = GLFW_KEY_F3;
            this->keyboard[45] = GLFW_KEY_F4;
            this->keyboard[46] = GLFW_KEY_F5;
            this->keyboard[47] = GLFW_KEY_F6;
            this->keyboard[48] = GLFW_KEY_F7;
            this->keyboard[49] = GLFW_KEY_F8;
            this->keyboard[50] = GLFW_KEY_F9;
            this->keyboard[51] = GLFW_KEY_F10;
            this->keyboard[52] = GLFW_KEY_F11;
            this->keyboard[53] = GLFW_KEY_F12;
            this->keyboard[54] = GLFW_KEY_F13;
            this->keyboard[55] = GLFW_KEY_F14;
            this->keyboard[56] = GLFW_KEY_F15;
            this->keyboard[57] = GLFW_KEY_F16;
            this->keyboard[58] = GLFW_KEY_F17;
            this->keyboard[59] = GLFW_KEY_F18;
            this->keyboard[60] = GLFW_KEY_F19;
            this->keyboard[61] = GLFW_KEY_F20;
            this->keyboard[62] = GLFW_KEY_F21;
            this->keyboard[63] = GLFW_KEY_F22;
            this->keyboard[64] = GLFW_KEY_F23;
            this->keyboard[65] = GLFW_KEY_F24;
            this->keyboard[66] = GLFW_KEY_F25;
            this->keyboard[67] = GLFW_KEY_UP;
            this->keyboard[68] = GLFW_KEY_DOWN;
            this->keyboard[69] = GLFW_KEY_LEFT;
            this->keyboard[70] = GLFW_KEY_RIGHT;
            this->keyboard[71] = GLFW_KEY_LSHIFT;
            this->keyboard[72] = GLFW_KEY_RSHIFT;
            this->keyboard[73] = GLFW_KEY_LCTRL;
            this->keyboard[74] = GLFW_KEY_RCTRL;
            this->keyboard[75] = GLFW_KEY_LALT;
            this->keyboard[76] = GLFW_KEY_RALT;
            this->keyboard[77] = GLFW_KEY_TAB;
            this->keyboard[78] = GLFW_KEY_ENTER;
            this->keyboard[79] = GLFW_KEY_BACKSPACE;
            this->keyboard[80] = GLFW_KEY_INSERT;
            this->keyboard[81] = GLFW_KEY_DEL;
            this->keyboard[82] = GLFW_KEY_PAGEUP;
            this->keyboard[83] = GLFW_KEY_PAGEDOWN;
            this->keyboard[84] = GLFW_KEY_HOME;
            this->keyboard[85] = GLFW_KEY_END;
            this->keyboard[86] = GLFW_KEY_KP_0;
            this->keyboard[87] = GLFW_KEY_KP_1;
            this->keyboard[88] = GLFW_KEY_KP_2;
            this->keyboard[89] = GLFW_KEY_KP_3;
            this->keyboard[90] = GLFW_KEY_KP_4;
            this->keyboard[91] = GLFW_KEY_KP_5;
            this->keyboard[92] = GLFW_KEY_KP_6;
            this->keyboard[93] = GLFW_KEY_KP_7;
            this->keyboard[94] = GLFW_KEY_KP_8;
            this->keyboard[95] = GLFW_KEY_KP_9;
            this->keyboard[96] = GLFW_KEY_KP_DIVIDE;
            this->keyboard[97] = GLFW_KEY_KP_MULTIPLY;
            this->keyboard[98] = GLFW_KEY_KP_SUBTRACT;
            this->keyboard[99] = GLFW_KEY_KP_ADD;
            this->keyboard[100] = GLFW_KEY_KP_DECIMAL;
            this->keyboard[101] = GLFW_KEY_KP_EQUAL;
            this->keyboard[102] = GLFW_KEY_KP_ENTER;
            this->keyboard[103] = GLFW_KEY_KP_NUM_LOCK;
            this->keyboard[104] = GLFW_KEY_CAPS_LOCK;
            this->keyboard[105] = GLFW_KEY_SCROLL_LOCK;
            this->keyboard[106] = GLFW_KEY_PAUSE;
            this->keyboard[107] = GLFW_KEY_LSUPER;
            this->keyboard[108] = GLFW_KEY_RSUPER;
            this->keyboard[109] = GLFW_KEY_MENU;

            int i = 0;    
            for(;i<this->keyboardLenght;i++)
            {
                this->eventKeyPressed[i] = false;
                this->previousKeyboardState[i] = false;
                this->currentKeyboardState[i] = false;
            }
        }

        if(this->setMouse)
        {
            this->mouse.reserve(8);
            this->eventMouseButtonsPressed.reserve(8);
            this->previousMouseButtonsState.reserve(8);
            this->currentMouseButtonsState.reserve(8);    

            this->mouse[0] = GLFW_MOUSE_BUTTON_LEFT;
            this->mouse[1] = GLFW_MOUSE_BUTTON_MIDDLE;
            this->mouse[2] = GLFW_MOUSE_BUTTON_RIGHT;
            this->mouse[3] = GLFW_MOUSE_BUTTON_4;
            this->mouse[4] = GLFW_MOUSE_BUTTON_5;
            this->mouse[5] = GLFW_MOUSE_BUTTON_6;
            this->mouse[6] = GLFW_MOUSE_BUTTON_7;
            this->mouse[7] = GLFW_MOUSE_BUTTON_8;
            
            int i = 0;    
            for(;i<this->mouseLenght;i++)
            {
                this->eventMouseButtonsPressed[i] = false;
                this->previousMouseButtonsState[i] = false;
                this->currentMouseButtonsState[i] = false;
            }
        }
    }

    m_pGlobalILayer = this;
}

cInputLayer::~cInputLayer(){
    /**
     * Previene el cualquier porximo intento de acceso a la clase graphics
     */
    cInputLayer::m_pGlobalILayer = NULL;
    delete cInputLayer::m_pGlobalILayer;
}

void cInputLayer::Create(int setKeyboard, int setMouse) {
    new cInputLayer(setKeyboard, setMouse); // Construye el objeto.
}

void cInputLayer::UpdateDevices()
{
    if(this->setKeyboard)
    {
        this->UpdateKeyboard();
    }
    if(this->setMouse)
    {
        this->UpdateMouse();
    }
}

void cInputLayer::UpdateKeyboard()
{
    int i = 0;
    
    // Obtener el estado actual del teclado
    for(; i < this->keyboardLenght; i++) {
        this->eventKeyPressed[i] = glfwGetKey(this->keyboard[i]);
    }
    
    //Hacer copia del estado actual del teclado
    for(i= 0; i < this->keyboardLenght; i++) {
        this->previousKeyboardState[i] = this->currentKeyboardState[i];
    }
    
    //Actualizar estado actual de teclado
    for(i = 0; i < this->keyboardLenght; i++) {
        this->currentKeyboardState[i] = this->eventKeyPressed[i];
    }
    
}

void cInputLayer::UpdateMouse()
{
    int i = 0;
    
    // Obtener el estado actual del teclado
    for(; i < this->mouseLenght; i++) {
        this->eventMouseButtonsPressed[i] = glfwGetMouseButton(this->mouse[i]);
    }
    
    //Hacer copia del estado actual de los botones del mouse
    for(i = 0; i < this->mouseLenght; i++) {
        this->previousMouseButtonsState[i] = this->currentMouseButtonsState[i];
    }
    
    //Actualizar estado actual de los botones del mouse
    for(i = 0; i < this->mouseLenght; i++) {
        this->currentMouseButtonsState[i] = this->eventMouseButtonsPressed[i];
    }
    
    //Actualizar posicion del mouse
    glfwGetMousePos(&this->eventMouseX, &this->eventMouseY);
    this->xPosRelative = this->eventMouseX - this->xPos;
    this->yPosRelative = this->eventMouseY - this->yPos;
    this->xPos = this->eventMouseX;
    this->yPos = this->eventMouseY;
}

bool cInputLayer::keyDown(int key)
{
    return this->currentKeyboardState[key];
}

bool cInputLayer::keyUp(int key)
{
    return this->previousKeyboardState[key] && !this->currentKeyboardState[key];
}

bool cInputLayer::keyPressed(int key)
{
    return !this->previousKeyboardState[key] && this->currentKeyboardState[key];
}

bool cInputLayer::buttonDown(int button)
{
    return this->currentMouseButtonsState[button];
}

bool cInputLayer::buttonUp(int button)
{
    return this->previousMouseButtonsState[button] && !this->currentMouseButtonsState[button];
}

bool cInputLayer::buttonPressed(int button)
{
    return !this->previousMouseButtonsState[button] && this->currentMouseButtonsState[button];
}